#include "TokenHierarchy.h"

using namespace std;

ostream& operator<<(ostream& cout, Token& token) {
	// Print out token on console
	cout << "Token ";

	// Switch typ of token
	switch (token.getTokenTyp()) {
		// This typs only need pointer of base class
		case TokenTyp::TOKEN_ALLOCATION:
		case TokenTyp::TOKEN_CLOSE_BRACKET:
		case TokenTyp::TOKEN_DIVISION:
		case TokenTyp::TOKEN_KOMMA:
		case TokenTyp::TOKEN_MINUS:
		case TokenTyp::TOKEN_MULTIPLICATION:
		case TokenTyp::TOKEN_OPEN_BRACKET:
		case TokenTyp::TOKEN_PLUS:
		case TokenTyp::TOKEN_SEMICOLON:
			cout << token.getName() << " | LINE: " << token.getLine() << " | COLUMN: " << token.getColumn() << endl;
			return cout;
			break;

		case TokenTyp::TOKEN_IDENT:
			// Warum eigentlich extra Block? Sonst kommt Compilerfehler C2360

			/*	Die Cases sind lediglich Sprungmarken und keine G¸ltigkeitsblˆcke!
			*	W¸rde man die geschweiften Klammern weglassen so w‰re z.b. der Zeiger tokenIdent auch im Case
			*	von TOKEN_LONG erreichbar, dort wurde der Zeiger aber nicht initialisiert.
			*	Deshalb weigert sich der Compiler ohne Blˆcke zu kompilieren.
			*
			*	Die geschweiften Klammern sind somit G¸ltigkeitsblˆcke und geben den G¸ltigkeitsbereich
			*	von Variablen an, die im Block initalisiert wurden. (n1ce 2 know)
			*/

			{// UM DIE HIER GEHTS!
				TokenIdent* tokenIdent = (TokenIdent*) &token;
				cout << tokenIdent->getName() << " | LINE: " << tokenIdent->getLine() << " | COLUMN: " << tokenIdent->getColumn() << " | LEXEM: " << tokenIdent->getLexem() << endl;
				return cout;
			}// UM DIE HIER GEHTS!
			break;

		case TokenTyp::TOKEN_INTEGER:
			{
				TokenInteger* tokenInteger = (TokenInteger*) &token;
				cout << tokenInteger->getName() << " | LINE: " << tokenInteger->getLine() << " | COLUMN: " << tokenInteger->getColumn() << " | VALUE: " << tokenInteger->getValue() << endl;
				return cout;
			}
			break;

		case TokenTyp::TOKEN_REAL:
			{
				TokenReal* tokenReal = (TokenReal*) &token;
				//cout.precision(10);
				cout << tokenReal->getName() << " | LINE: " << tokenReal->getLine() << " | COLUMN: " << tokenReal->getColumn() << " | VALUE: " << tokenReal->getValue() << endl;
				return cout;
			}
			break;

		case TokenTyp::TOKEN_PROD:
			{
				TokenProduct* tokenProduct = (TokenProduct*) &token;
				cout << tokenProduct->getName() << " | LINE: " << tokenProduct->getLine() << " | COLUMN: " << tokenProduct->getColumn() << endl;
				return cout;
			}
			break;

		case TokenTyp::TOKEN_SUM:
			{
				TokenSum* tokenSum = (TokenSum*) &token;
				cout << tokenSum->getName() << " | LINE: " << tokenSum->getLine() << " | COLUMN: " << tokenSum->getColumn() << endl;
				return cout;
			}
			break;
			
		case TokenTyp::TOKEN_PRINT:
			{
				TokenPrint* tokenSum = (TokenPrint*) &token;
				cout << tokenSum->getName() << " | LINE: " << tokenSum->getLine() << " | COLUMN: " << tokenSum->getColumn() << endl;
				return cout;
			}
			break;
		case TokenTyp::TOKEN_MODULO:
			{
				TokenModulo* tokenSum = (TokenModulo*) &token;
				cout << tokenSum->getName() << " | LINE: " << tokenSum->getLine() << " | COLUMN: " << tokenSum->getColumn() << endl;
				return cout;
			}
			break;
			
		case TokenTyp::TOKEN_DURCH:
			{
				TokenDurch* tokenSum = (TokenDurch*) &token;
				cout << tokenSum->getName() << " | LINE: " << tokenSum->getLine() << " | COLUMN: " << tokenSum->getColumn() << endl;
				return cout;
			}
			break;
		

		default:
			// Unknown token
			return cout << "Unknown Token! Token couldn't be printed!" << endl;
			break;
	}
}